package com.umakr.ax.oss.service;

import com.alibaba.fastjson.JSON;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.OSSObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jxl.biff.AutoFilterInfoRecord;
import jxl.common.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author umakr
 */
@Service
public class StsServiceSample {
    private static Logger logger = Logger.getLogger(AutoFilterInfoRecord.class);

    @Value("${msg.oss.accessKeyId}")
    String accessKeyId;
    @Value("${msg.oss.accessKeySecret}")
    String accessKeySecret;
    @Value("${msg.oss.roleArn}")
    String roleArn;
    @Value("${fileupload.ali.bucketname}")
    String bucketName;
    @Value("${fileupload.ali.path}")
    String fileUploadBasePath;

    private static final String CACHE_LASTREFRESHTIMESTAMP = "lastRefreshTimeStamp";
    private static final Integer TIME_STAMP_MIN = 50;
    private static final Integer TIME_STAMP_SEC = 60;
    private static final Integer TIME_STAMP_RATE = 1000;
    private static final String ERRORCODE = "errorCode";

    /**
     * 目前只有"cn-hangzhou"这个region可用, 不要使用填写其他region的值
     */
    public static final String REGION_CN_HANGZHOU = "cn-hangzhou";
    /**
     * 当前 STS API 版本
     * 2018-01-11T14:56:35Z
     */
    public static final String STS_API_VERSION = "2015-04-01";

    /**
     *  SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-ddTHH:mm:ssZ");
     */
    Map<String,Object> cache = Maps.newHashMap();
    private AssumeRoleResponse assumeRole(String accessKeyId, String accessKeySecret,
                                         String roleArn, String roleSessionName, String policy,
                                         ProtocolType protocolType) throws ClientException {
        try {
            // 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
            IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
            DefaultAcsClient client = new DefaultAcsClient(profile);

            // 创建一个 AssumeRoleRequest 并设置请求参数
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setVersion(STS_API_VERSION);
            request.setMethod(MethodType.POST);
            request.setProtocol(protocolType);
            request.setAcceptFormat(FormatType.JSON);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy);
            request.setDurationSeconds(60*60L);
            // 发起请求，并得到response

            return client.getAcsResponse(request);
        } catch (ClientException e) {
            logger.error(e);
            throw e;
        }
    }
    public Map<String,Object> getOssToken(Long userId){
        return get(userId+"-real");
    }
    private Map<String,Object> get(String roleSessionName) {
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        // 此处必须为 HTTPS
        ProtocolType protocolType = ProtocolType.HTTPS;
        Map<String,Object> policyMap = Maps.newHashMap();
        policyMap.put("Version","1");

        Map<String,Object> statementContent = Maps.newHashMap();
        List<Map<String,Object>> statementList = Lists.newArrayList();
        statementList.add(statementContent);

        policyMap.put("Statement",statementList);

        List<String> actionList = Lists.newArrayList();

        actionList.add("oss:DeleteObject");
        actionList.add("oss:ListParts");
        actionList.add("oss:AbortMultipartUpload");
        actionList.add("oss:PutObject");

        statementContent.put("Action",actionList);

        //acs:oss:*:*:*
        List<String> resourceList = Lists.newArrayList();
        resourceList.add("acs:oss:*:*:test22umake1");
        resourceList.add("acs:oss:*:*:test22umake1/*");
        statementContent.put("Resource",resourceList);
        statementContent.put("Effect","Allow");
        logger.info(JSON.toJSONString(policyMap));
        Map<String,Object> result = Maps.newHashMap();
        result.put(ERRORCODE,1);
        if(cache.get(CACHE_LASTREFRESHTIMESTAMP)!=null){
            Long time = Long.parseLong(cache.get(CACHE_LASTREFRESHTIMESTAMP).toString());
            // 超过50分钟则重新获取
            if(System.currentTimeMillis() - time < TIME_STAMP_MIN * TIME_STAMP_SEC * TIME_STAMP_RATE){
                cache.put("currentTimeStamp",System.currentTimeMillis());
                result.put("data",cache);
                return result;
            }
        }
        try {
            final AssumeRoleResponse response = assumeRole(accessKeyId, accessKeySecret,
                    roleArn, roleSessionName, policy, protocolType);
            logger.info("Expiration: " + response.getCredentials().getExpiration());
            cache.put(CACHE_LASTREFRESHTIMESTAMP,System.currentTimeMillis());
            logger.info("Access Key Id: " + response.getCredentials().getAccessKeyId());
            cache.put("accessKeyId",response.getCredentials().getAccessKeyId());
            logger.info("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
            cache.put("accessKeySecret",response.getCredentials().getAccessKeySecret());

            logger.info("securityToken: " + response.getCredentials().getSecurityToken());
            cache.put("securityToken",response.getCredentials().getSecurityToken());
            cache.put("currentTimeStamp",System.currentTimeMillis());
        } catch (ClientException e) {
            result.put(ERRORCODE,0);
            logger.info("Failed to get a token.");
            logger.info("Error code: " + e.getErrCode());
            logger.info("Error message: " + e.getErrMsg());
        }
        result.put("data",cache);
        return result;
    }

    public Object fileUpload(Long userId, MultipartFile file, String filePath){

        String fileName = file.getOriginalFilename();
        String suffix = fileName.substring(fileName.lastIndexOf('.'));
        fileName = System.currentTimeMillis() + suffix;

        OSS ossClient = creactBucket(userId);

        if(filePath == null){
            filePath = fileUploadBasePath;
        }

        Map<String,Object> resultMap = Maps.newHashMap();
        try {
            ossClient.putObject(bucketName, filePath+fileName, file.getInputStream());
            OSSObject ossObject = ossClient.getObject(bucketName,fileUploadBasePath+fileName);

            Map<String,String> map = Maps.newHashMap();
            map.put("upUrl",ossObject.getKey());
            resultMap.put("data",map);
            resultMap.put("msg","上传成功");
            resultMap.put(ERRORCODE,1);

            ossClient.shutdown();
        } catch (IOException e) {
            logger.info(e);
            resultMap.put("msg","上传失败");
            resultMap.put(ERRORCODE,0);
        }
        return resultMap;
    }

    public Object fileUpload(Long userId, File file, String filePath){

        String fileName = file.getName();
        String suffix = fileName.substring(fileName.lastIndexOf('.'));
        fileName = System.currentTimeMillis() + suffix;

        OSS ossClient = creactBucket(userId);

        if(filePath == null){
            filePath = fileUploadBasePath;
        }

        return upload( ossClient, filePath, fileName, file);

    }

    public Object fileUploads(Long userId, File file, String filePath){

        String fileName = file.getName();
        OSS ossClient = creactBucket(userId);

        if(filePath == null){
            filePath = fileUploadBasePath;
        }

        return upload( ossClient, filePath, fileName, file);

    }

    private OSS creactBucket(Long userId){
        Map<String,Object> tokenMap = getOssToken(userId);
        tokenMap = (Map<String,Object>)tokenMap.get("data");
        String accessKeyIdToken = tokenMap.get("accessKeyId").toString();
        String accessKeySecretToken = tokenMap.get("accessKeySecret").toString();
        String securityToken = tokenMap.get("securityToken").toString();

        OSS ossClient = new OSSClient("http://oss-cn-beijing.aliyuncs.com", accessKeyIdToken, accessKeySecretToken,securityToken);

        if (ossClient.doesBucketExist(bucketName)) {
            logger.info("您已经创建Bucket：" + bucketName + "。");
        } else {
            logger.info("您的Bucket不存在，创建Bucket：" + bucketName + "。");
            // 创建Bucket。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。
            // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init
            ossClient.createBucket(bucketName);
        }

        return ossClient;
    }
    private Map<String,Object> upload(OSS ossClient,String filePath,String fileName,File file){
        Map<String,Object> resultMap = Maps.newHashMap();
        try {
            ossClient.putObject(bucketName, filePath+fileName, new FileInputStream(file));
            OSSObject ossObject = ossClient.getObject(bucketName,filePath+fileName);

            Map<String,String> map = Maps.newHashMap();
            map.put("upUrl",ossObject.getKey());
            resultMap.put("data",map);
            resultMap.put("msg","上传成功");
            resultMap.put(ERRORCODE,1);

            ossClient.shutdown();
        } catch (IOException e) {
            logger.info(e);
            resultMap.put("msg","上传失败");
            resultMap.put(ERRORCODE,0);
        }
        return resultMap;
    }

}
